#ifndef AUTOPTR_H
#define AUTOPTR_H

#include <QtCore/qatomic.h>
#include <QtCore/qobject.h>

template<class T>
class Basic
{
public:
    typedef T Type;

    inline T *data()const {return value;}

    inline bool isNull() const {return !data();}

    inline bool operator !() const {return isNull();}

    inline T& operator *() const {return *data();}

    inline T* operator ->() const {return data();}

    inline void internalConstruct(T *ptr)
    {
        value = ptr;
    }

protected:
    Basic(T *ptr):value(ptr) {}
    Basic() {}

private:
    Type *value;
};

struct ExternalRefCountData
{
    QBasicAtomicInt weakref;
    QBasicAtomicInt strongref;

    inline ExternalRefCountData()
    {
        strongref = 1;
        weakref = 1;
    }
    inline ExternalRefCountData(Qt::Initialization) { }
    virtual inline ~ExternalRefCountData() { Q_ASSERT(!weakref); Q_ASSERT(strongref <= 0); }

    virtual inline bool destroy() { return false; }

    inline void setQObjectShared(...) { }
};

template<class T>
class ExternalRefCount:public Basic<T>
{
protected:
    typedef ExternalRefCountData Data;

    inline void deref(){
        deref(d,this->value);
    }
    static inline void deref(Data *d,T *value){
        if(!d) return;
        if(!d->strongref.deref()){
            if(!d->destroy()){
                delete value;
            }
        }
        if(!d->weakref.deref()){
            delete d;
        }
    }

    inline void internalConstruct(T *ptr)
    {
      if (ptr)
        d = new Data;
      else
        d = 0;
      internalFinishConstruction(ptr);
    }

    inline void internalFinishConstruction(T *ptr)
    {
        Basic<T>::internalConstruct(ptr);
        if (ptr) d->setQObjectShared(ptr, true);
    }

    inline ExternalRefCount() : d(0) { }

    inline ExternalRefCount(T *ptr) : Basic<T>(Qt::Uninitialized) // throws
    { internalConstruct(ptr); }

    inline ExternalRefCount(const ExternalRefCount<T> &other) : Basic<T>(other), d(other.d)
    { if (d) ref(); }

    template <class X>
    inline ExternalRefCount(const ExternalRefCount<X> &other) : Basic<T>(other.value), d(other.d)
    { if (d) ref(); }

    inline virtual ~ExternalRefCount() { deref(); }

    inline void ref() const { d->weakref.ref(); d->strongref.ref(); }

    inline void internalSet(Data *o, T *actual)
    {
        if (o) {
            // increase the strongref, but never up from zero
            // or less (-1 is used by QWeakPointer on untracked QObject)
            int tmp = o->strongref;
            while (tmp > 0) {
                // try to increment from "tmp" to "tmp + 1"
                if (o->strongref.testAndSetRelaxed(tmp, tmp + 1))
                    break;   // succeeded
                tmp = o->strongref;  // failed, try again
            }

            if (tmp > 0)
                o->weakref.ref();
            else
                o = 0;
        }

        qSwap(d, o);
        qSwap(this->value, actual);
        if (!d || d->strongref == 0)
            this->value = 0;

        // dereference saved data
        deref(o, actual);
    }

    template <class X>
    inline void internalCopy(const ExternalRefCount<X> &other)
    {
        Data *o = other.d;
        T *actual = other.value;
        if (o)
            other.ref();
        qSwap(d, o);
        qSwap(this->value, actual);
        deref(o, actual);
    }

    inline void internalSwap(ExternalRefCount &other)
    {
        qSwap(d, other.d);
        qSwap(this->value, other.value);
    }

    Data *d;

private:

};

template<class T>
class AutoPtr
{
public:
    inline AutoPtr(){value = NULL;}
    inline AutoPtr(T *pointer){value = pointer;}
    inline AutoPtr(const AutoPtr<T> &other){
        this->value = other.value;
    }
    inline AutoPtr<T> &operator= (const AutoPtr<T> &other){
        this->value = other.value;
        return *this;
    }
    inline AutoPtr<T> &operator=(AutoPtr<T> &other)
    {
        this->value = other.value;
        return *this;
    }

    inline AutoPtr<T> &operator = (T *other){
        this->value = other;
        return *this;
    }

    inline T *data()const {return value;}

    inline bool isNull() const {return !data();}

    inline bool operator !() const {return isNull();}

    inline T& operator *() const {return *data();}

    inline T* operator ->() const {return data();}

private:
    T *value;

};

#endif // AUTOPTR_H
